package main

import (
	"crypto/md5"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"io"
	"net"
	"time"

	"github.com/pushdotccgzs/coapmsg"
	"github.com/satori/go.uuid"
)

func NewDeviceUUID() string {
	return uuid.NewV1().String()
}

func NewAppKey() string {
	return sha512Str(uuid.NewV1().String())
}

func TokenInteger(token string) int {
	data := []byte(token)
	var sum int
	for _, i := range data {
		sum += int(i)
	}
	return sum
}

func MessageStatDisplay(stat string) string {
	dict := map[string]string{
		"CREATED":  "已创建",
		"SENT":     "已发送",
		"UPLOADED": "已接收",
		"PLANING":  "计划发送",
	}
	v, ok := dict[stat]
	if !ok {
		return "未知"
	}
	return v
}

func MsgDirectionStr(direction uint) string {
	if direction == MESSAGE_DIRECTION_DOWN {
		return "DOWN"
	}
	return "UP"
}

func NewAuthTokenUUID() string {
	return md5str(uuid.NewV1().String())
}

func TimeToString(t time.Time) string {
	return t.Format("2006-01-02 15:04:05")
}

func md5str(src string) string {
	ctx := md5.New()
	ctx.Write([]byte(src))
	return hex.EncodeToString(ctx.Sum(nil))
}

func sha512Str(src string) string {
	h := sha512.New()
	h.Write([]byte(src))
	return hex.EncodeToString(h.Sum(nil))
}

func sendCoAP(msg coapmsg.Message, sock *net.UDPConn, addr net.UDPAddr) (err error) {
	//logger.Infof("SEND\n%s\n", ShowCoAP(msg))
	buf, err := coapmsg.MessageToBytes(msg)
	if err != nil {
		fmt.Println("message serialize failed.")
		return
	}

	_, err = sock.WriteToUDP(buf, &addr)
	if err != nil {
		fmt.Println("send coap to client failed.")
		return
	}
	//fmt.Printf("SEND [%d][%s]\n", snd, byte2Hex(buf))
	return
}

func MessageReqRsp(msg coapmsg.Message) string {
	var rsp string
	code := msg.GetCode()
	methods := map[uint8]string{
		1: "GET",
		2: "POST",
	}
	if code <= 10 {
		rsp = "REQ "
		if v, ok := methods[uint8(code)]; ok {
			rsp += v
		} else {
			rsp += "UNKNOWN"
		}
	} else {
		rsp = "RSP " + fmt.Sprintf("%d", code)
	}
	return rsp
}

func MessageTypeString(msg coapmsg.Message) string {
	types := map[uint8]string{
		0: "CON",
		1: "NON",
		2: "ACK",
		3: "RST",
	}
	msgtype := msg.GetMessageType()
	if v, ok := types[msgtype]; ok {
		return v
	} else {
		return "UNKNOWN"
	}
}

func optionString(opt coapmsg.Option) string {
	return fmt.Sprintf("%d %v", opt.GetCode(), opt.GetValue())
	//return fmt.Sprintf("%d %s", opt.GetCode(), opt.GetValue().(string))
}

func ShowCoAP(msg coapmsg.Message) string {
	var rsp string
	rsp = fmt.Sprintf("\t%s %s ID %d TOKEN %d,%s\n", coapmsg.CoapCodeToString(msg.GetCode()), MessageTypeString(msg), msg.GetMessageId(), msg.GetTokenLength(), msg.GetTokenString())
	rsp += "\tOPTIONS "
	opts := msg.GetAllOptions()
	for _, opt := range opts {
		rsp += optionString(opt)
		rsp += " "
	}
	rsp += "\n"
	if msg.GetPayload() != nil {
		rsp += fmt.Sprintf("\tPAYLOAD %d,%s", msg.GetPayload().Length(), byte2Hex(msg.GetPayload().GetBytes()))
	} else {
		rsp += "\tpayload nil"
	}
	return rsp
}

func NewMsgHash(msgid uint16, token string) string {
	h := md5.New()
	io.WriteString(h, fmt.Sprintf("%05d", msgid))
	io.WriteString(h, token)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func byte2Hex(data []byte) string {
	var rsp string
	for _, val := range data {
		rsp += fmt.Sprintf("%02X", val)
	}
	return rsp
}

func assert(b bool) {
	if !b {
		panic("assert failed.")
	}
}
